﻿using System;
using System.Text;
using System.Collections.Generic;
using System.Linq;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using FeatureModelCore;
using System.IO;
using System.Xml.Linq;
using FeatureModelCore.FMAnalyzer;
using FeatureModelCore.Optimized;
using FeatureModelCore.FMInterface;
using Collections.TreeCollections;
using FeatureModelCore.FMExceptions;
using FeatureModelCore.FMCrossTreeConstraint;

namespace FeatureModelTest
{
    [TestClass]
    public class TestFeatureModel
    {
        [TestMethod]
        public void TestFeatureModelConstruct()
        {
            FeatureModelTree fm = GenerateTestCases.GenerateFeatureModel();
            //FeatureModelValider valider = new FeatureModelValider(fm);
            //bool isValid = valider.ValidHierarchy();

            //Assert.IsTrue(isValid);
        }
        [TestMethod]
        public void TestFeatureModelExtension()
        {
            FeatureModelTree fm = GenerateTestCases.GenerateFeatureModel();

            // mobile
            IFeature mobilePhone = fm.GetFeatureNode(GenerateTestCases.MOBILE_PHONE);
            Assert.IsTrue(mobilePhone.ObjectExtension.AllCrossTreeConstraints.Length == 2);
            Assert.IsTrue(mobilePhone.ObjectExtension.OuterConstraint.Length == 0);
            Assert.IsTrue(mobilePhone.ObjectExtension.AllCrossTreeConstraints[0].InfoType
                == FeatureModelCore.FMCrossTreeConstraint.CrossTreeConstraintInfoType.Current);
            Assert.IsTrue(mobilePhone.ObjectExtension.AllCrossTreeConstraints[0].InfoType
                == FeatureModelCore.FMCrossTreeConstraint.CrossTreeConstraintInfoType.Current);

            // call
            IFeature call = fm.GetFeatureNode(GenerateTestCases.CALLS);
            Assert.IsTrue(call.ObjectExtension.AllCrossTreeConstraints.Length == 0);
            Assert.IsTrue(call.ObjectExtension.OuterConstraint.Length == 0);

            // gps
            IFeature gps = fm.GetFeatureNode(GenerateTestCases.GPS);
            Assert.IsTrue(gps.ObjectExtension.AllCrossTreeConstraints.Length == 1);
            Assert.IsTrue(gps.ObjectExtension.OuterConstraint.Length == 1);


            // screen
            IFeature screen = fm.GetFeatureNode(GenerateTestCases.SCREEN);
            Assert.IsTrue(screen.ObjectExtension.AllCrossTreeConstraints.Length == 2);
            Assert.IsTrue(screen.ObjectExtension.OuterConstraint.Length == 2);

            // basic
            IFeature basic = fm.GetFeatureNode(GenerateTestCases.BASIC);
            Assert.IsTrue(basic.ObjectExtension.AllCrossTreeConstraints.Length == 1);
            Assert.IsTrue(basic.ObjectExtension.OuterConstraint.Length == 1);


            // color
            IFeature color = fm.GetFeatureNode(GenerateTestCases.COLOUR);
            Assert.IsTrue(color.ObjectExtension.AllCrossTreeConstraints.Length == 0);
            Assert.IsTrue(color.ObjectExtension.OuterConstraint.Length == 0);

            // high resolution
            IFeature highResolution = fm.GetFeatureNode(GenerateTestCases.HIGH_RESOLUTION);
            Assert.IsTrue(highResolution.ObjectExtension.AllCrossTreeConstraints.Length == 1);
            Assert.IsTrue(highResolution.ObjectExtension.OuterConstraint.Length == 1);

            // media
            IFeature media = fm.GetFeatureNode(GenerateTestCases.MEDIA);
            Assert.IsTrue(media.ObjectExtension.AllCrossTreeConstraints.Length == 1);
            Assert.IsTrue(media.ObjectExtension.OuterConstraint.Length == 1);

            // camera
            IFeature camera = fm.GetFeatureNode(GenerateTestCases.CAMERA);
            Assert.IsTrue(camera.ObjectExtension.AllCrossTreeConstraints.Length == 1);
            Assert.IsTrue(camera.ObjectExtension.OuterConstraint.Length == 1);

            // mp3
            IFeature mp3 = fm.GetFeatureNode(GenerateTestCases.MP3);
            Assert.IsTrue(mp3.ObjectExtension.AllCrossTreeConstraints.Length == 0);
            Assert.IsTrue(mp3.ObjectExtension.OuterConstraint.Length == 0);
        }
        [TestMethod]
        public void TestFeatureModelRemoveExtension()
        {
            FeatureModelTree fm = GenerateTestCases.GenerateFeatureModel();
            fm.DeleteCrossTreeConstraint(fm.AllCrossTreeConstraints[0]);
            fm.DeleteCrossTreeConstraint(fm.AllCrossTreeConstraints[0]);

            Assert.IsTrue(fm.AllCrossTreeConstraints.Length == 0);
            foreach (IFeature treeObj in fm.AllFeatureNodes)
            {
                Assert.IsTrue(
                    treeObj.ObjectExtension.AllCrossTreeConstraints.Length == 0);
            }
        }
        [TestMethod]
        public void TestFeatureModel2File()
        {
            string output1 = "output1.xml";
            FeatureModelTree fm = GenerateTestCases.GenerateFeatureModel();
            
            XDocument xdoc = fm.ToXDoc();
            string fmStr = xdoc.ToString();

            using(StreamWriter writer = File.CreateText(output1))
            {
                writer.WriteLine(xdoc);
            }
            FeatureModelTree fm_ = FeatureModelTree.XDocParser(xdoc);
            Assert.IsTrue(fm_.TreeHierarchyEquals(fm));
        }
        [TestMethod]
        public void TestFeatureModelClone()
        {
            FeatureModelTree fm = GenerateTestCases.GenerateFeatureModel();
            FeatureModelTree fm_ = (FeatureModelTree)fm.Clone();
            Assert.IsTrue(fm.TotallyEquals(fm_));
        }
        [TestMethod]
        public void TestFeatureModelToProducts()
        {
            FeatureModelTree fm = GenerateTestCases.GenerateFeatureModelOnlyOneAlternativeGroup();
            FMProductCollection ret = fm.AllProducts(); 
            Assert.IsTrue(ret.Count == 4);

            fm = GenerateTestCases.GenerateFeatureModelOnlyOneOrGroup();
            ret = fm.AllProducts();  // 15
            Assert.IsTrue(ret.Count == 15);

            fm = GenerateTestCases.GenerateFeatureModelOnlyOneMandatoryGroup();
            ret = fm.AllProducts(); // 1
            Assert.IsTrue(ret.Count == 1);

            fm = GenerateTestCases.GenerateFeatureModelOnlyOneOptionalGroup();
            ret = fm.AllProducts(); // 1
            Assert.IsTrue(ret.Count == 4);

            fm = GenerateTestCases.GenerateFeatureModelWithNoConstraint();
            ret = fm.AllProducts(); 

            fm = GenerateTestCases.GenerateFeatureModel();
            ret = fm.AllProducts(); 
            Assert.IsTrue(ret.Count == 14);
        }
        [TestMethod]
        public void TestOptimizedFeatureModelTreeTest()
        {
            FeatureModelTree fm = GenerateTestCases.GenerateFeatureModel();
            OptimizedFeatureModel oFM = new OptimizedFeatureModel(fm);


        }
        [TestMethod]
        public void TestDeleteInstance()
        {
            FeatureModelTree fm = GenerateTestCases.GenerateFeatureModel();
            IFeature calls = fm.GetFeatureNode(GenerateTestCases.CALLS);
            fm.DeleteExistInstance((INonRoot)calls);
            Assert.IsTrue(fm.AllFeatureNodes.Length == 9);
            Assert.IsTrue(fm.AllCrossTreeConstraints.Length == 2);


            fm = GenerateTestCases.GenerateFeatureModel();
            IFeature gps = fm.GetFeatureNode(GenerateTestCases.GPS);
            fm.DeleteExistInstance((INonRoot)gps);
            Assert.IsTrue(fm.AllFeatureNodes.Length == 9);
            Assert.IsTrue(fm.AllCrossTreeConstraints.Length == 1);

            try
            {
                fm = GenerateTestCases.GenerateFeatureModel();
                IFeature screen = fm.GetFeatureNode(GenerateTestCases.SCREEN);
                fm.DeleteExistInstance((INonRoot)screen);
                Assert.IsTrue(false);
            }
            catch (ExistedInstanceDeletionException)
            {
                Assert.IsTrue(fm.AllFeatureNodes.Length == 10);
                Assert.IsTrue(fm.AllCrossTreeConstraints.Length == 2);
            }

            fm = GenerateTestCases.GenerateFeatureModel();
            IFeature media = fm.GetFeatureNode(GenerateTestCases.MEDIA);
            fm.DeleteExistInstance((INonRoot)media);
            Assert.IsTrue(fm.AllFeatureNodes.Length == 7);
            Assert.IsTrue(fm.AllCrossTreeConstraints.Length == 1);

            fm = GenerateTestCases.GenerateFeatureModel();
            IFeature basic = fm.GetFeatureNode(GenerateTestCases.BASIC);
            fm.DeleteExistInstance((INonRoot)basic);
            Assert.IsTrue(fm.AllFeatureNodes.Length == 9);
            Assert.IsTrue(fm.AllCrossTreeConstraints.Length == 1);

            fm = GenerateTestCases.GenerateFeatureModel();
            IFeature color = fm.GetFeatureNode(GenerateTestCases.COLOUR);
            fm.DeleteExistInstance((INonRoot)color);
            Assert.IsTrue(fm.AllFeatureNodes.Length == 9);
            Assert.IsTrue(fm.AllCrossTreeConstraints.Length == 2);

            try
            {
                fm = GenerateTestCases.GenerateFeatureModel();
                IFeature highRes = fm.GetFeatureNode(GenerateTestCases.HIGH_RESOLUTION);
                fm.DeleteExistInstance((INonRoot)highRes);
                Assert.IsTrue(false);
            }
            catch (ExistedInstanceDeletionException)
            {
                Assert.IsTrue(fm.AllFeatureNodes.Length == 10);
                Assert.IsTrue(fm.AllCrossTreeConstraints.Length == 2);
            }

            fm = GenerateTestCases.GenerateFeatureModel();
            IFeature camera = fm.GetFeatureNode(GenerateTestCases.CAMERA);
            fm.DeleteExistInstance((INonRoot)camera);
            Assert.IsTrue(fm.AllFeatureNodes.Length == 9);
            Assert.IsTrue(fm.AllCrossTreeConstraints.Length == 1);

            fm = GenerateTestCases.GenerateFeatureModel();
            IFeature mp3 = fm.GetFeatureNode(GenerateTestCases.MP3);
            fm.DeleteExistInstance((INonRoot)mp3);
            Assert.IsTrue(fm.AllFeatureNodes.Length == 9);
            Assert.IsTrue(fm.AllCrossTreeConstraints.Length == 2);

            fm = GenerateTestCases.GenerateFeatureModel();
            foreach (CrossTreeConstraint tmpCons in fm.AllCrossTreeConstraints)
            {
                if (tmpCons.Type == FeatureModelCore.FMTypes.FMCrossTreeConstraintType.Require)
                {
                    fm.DeleteCrossTreeConstraint(tmpCons);
                    break;
                }
            }
            IFeature screen2 = fm.GetFeatureNode(GenerateTestCases.SCREEN);
            fm.DeleteExistInstance((INonRoot)screen2);
            Assert.IsTrue(fm.AllFeatureNodes.Length == 6);
            Assert.IsTrue(fm.AllCrossTreeConstraints.Length == 0);
        }
    }
}
